home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 30
/
Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso
/
Aminet
/
util
/
arc
/
CheckX.lha
/
CheckX
/
sources
/
CheckX.c
next >
Wrap
C/C++ Source or Header
|
1999-02-11
|
50KB
|
1,707 lines
#define NAME "CheckX"
#define REVISION "47"
#define DISTRIBUTION "(Freeware) "
/*
When someone uses the here shown methods for own programs, he has to
contact me first and always to mention me in his program documentation!
This program scans for crunched, linked files and archived files. It
decrunches them and saves the result files to another directory-tree.
The scanning routines are recursiv and thus check really all stuff. Linked
files are saved with .1, .2, ... additions.
The main purpose it was written for is to scan for crunched files and to
test the decrunch routines. So the logging may take some more time, but is
very stable, as the last log-entry is always the file which possibly
crashed the machine.
Address crunched programs are decrunched as well, but not saved. Use
xfdDecrunch or xfdDecrunchAddr to generate decrunched executable files
of this type (with correct header information).
Especially in UNARCHIVE mode this tool may need lots of memory (when T: is
assigned to ram disk). Keep that in mind! Every checked file is completely
loaded into memory!
CheckX cannot scan files, which are read-protected. You get CheckX error 106
as result in that case. Unprotect files and scan again when you want.
NOTE: SaveDir must exist already, only sub-dirs are created.
The program must be compiled and linked without startup-code. You can set
the pure file protection bit and make it resident, because it is multi-
reentrant (no global variables, except library bases).
This means it can be called multiple times as well, but this is not
recommended, as said above CheckX needs lots of memory.
Disk archives are handled this way:
They are unarchived to RD0: in depth1, to RD1: in depth2 (when archive is
in RD0:) and to RD2: in depth3, ....
NOTE: accessing RD0:, RD1 or RD2: during this time may produce errors.
This includes starting CheckX twice, when scanning disk archives. For high
density archives the archive names are RH1:, RH2:, ...
Splitted DMS-Archives may produce strange errors, but can be checked
correctly, when the two parts are directly after another (e.g. no other
track archive is between them). In this case the first file shows some
XPKCERR_READWRITE and the second one the correct stuff.
Crypted archives are not supported yet (e.g. asking for password).
*/
/* Programmheader
Name: CheckX
Author: SDI
Distribution: Freeware
Description: scans and decrunches crunched files with xfd
Compileropts: -
Linkeropts: -l xpkmaster amiga -gsi
Plans: add new archivers, xadmaster.library support
1.0 14.12.96 : first Version
1.1 28.12.96 : moved PassRequest into xpkmaster.library
1.2 12.02.97 : now also decrunches Exe-Files
1.3 15.06.97 : added length output as test
1.4 21.11.97 : renamed from Decrunch, got really new program
1.5 22.11.97 : bug-fixes
1.6 29.11.97 : added unarchiving feature
1.7 30.11.97 : bug-fixes
1.8 06.12.97 : xpkmaster.library now only required with ASKPWD option
1.9 07.12.97 : Added archive copy for weird archive names, better error
codes
1.10 08.12.97 : fixed error codes a bit
1.11 11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
to temporary filenames
1.12 12.12.97 : added Arc, ZOO and LhASFX archives
1.13 13.12.97 : fixed Arc recognition
1.14 19.12.97 : deletes copied arc before scan
1.15 22.12.97 : crunched archives are unarchived correctly now
1.16 02.01.98 : opens dos.library itself, no startup-code required
1.17 23.01.98 : added disk crunchers
1.18 24.01.98 : some fixes
1.19 01.02.98 : little bug-fix in argument-option use
1.20 06.02.98 : better error output, added automount
1.21 08.02.98 : little bug-fix
1.22 10.02.98 : fixed archive copy conditions, added PRINTALL
1.23 12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
1.24 13.02.98 : added unstripping
1.25 04.03.98 : added PRINTEXEC
1.26 13.03.98 : added high density DMS support
1.27 19.03.98 : added LOUD keyword
1.28 23.03.98 : RDx no longer depends on archive depth, but on dddepth
1.29 10.04.98 : bug fixes
1.30 26.04.98 : bug fixes
1.31 09.05.98 : now uses no longer adress 4 for SysBase
1.32 31.05.98 : better output
1.33 04.06.98 : added HEADER addition for address files
1.34 08.08.98 : bug fix with SAVE
1.35 24.09.98 : added xvs.library virus checks
1.36 18.10.98 : xvs is opened global and only once
1.37 30.10.98 : renamed from CheckXFD
1.38 11.11.98 : fixed format drive bug using a delay and an error report
1.39 14.11.98 : format error with AUTOMOUNT removed
1.40 16.11.98 : removed HEADER addition stuff
1.41 18.11.98 : better RDx: access and mount
1.42 23.11.98 : fixed bug with hunk stripping
1.43 29.12.98 : now prints an error, when virus detection is turned off,
added time calculation and output
1.44 31.12.98 : little bug fix
1.45 06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
and internal DMS call
1.46 09.02.99 : removed internal LZX call
1.47 11.02.99 : now uses assembler startcode allocating a bigger stack
*/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/xfdmaster.h>
#include <proto/xadmaster.h>
#include <proto/xpkmaster.h>
#include <proto/intuition.h>
#include <proto/xvs.h>
#include <libraries/xfdmaster.h>
#include <dos/dostags.h>
#include <dos/doshunks.h>
#include <exec/memory.h>
#include "SDI_defines.h" /* make version string */
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#define PARAM "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,AUTOMOUNT/S,PRINTALL/S," \
"PRINTEXEC/S," \
"NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S," \
"NOTRACKCUT/S,NOSTRIP/S,NOVIRUS/S"
#ifdef __SASC
#define XpkBase xpkbase
#define ASSIGN_XPK
#define IntuitionBase intuitionbase
#define ASSIGN_INT
#else
struct Library * XpkBase = 0;
struct IntuitionBase *IntuitionBase = 0;
#define ASSIGN_XPK XpkBase = xpkbase;
#define ASSIGN_INT IntuitionBase = intuitionbase;
#endif
struct xfdMasterBase * xfdMasterBase = 0;
struct DosLibrary * DOSBase = 0;
struct ExecBase * SysBase = 0;
struct xvsBase * xvsBase = 0;
struct xadMasterBase * xadMasterBase = 0;
struct Args {
STRPTR from;
STRPTR log;
STRPTR save;
ULONG all;
ULONG askpwd;
ULONG automount;
ULONG printall;
ULONG printexec;
ULONG nodecrunch;
ULONG nounlink;
ULONG nounarchive;
ULONG nountrack;
ULONG notrackcut;
ULONG nostrip;
ULONG novirus;
};
struct CrunchMemList {
struct CrunchMemList * cml_Next;
APTR cml_MemoryRegion;
ULONG cml_MemorySize;
};
#define XFDCHECKFLAG_SAVE (1<< 0)
#define XFDCHECKFLAG_ALL (1<< 1)
#define XFDCHECKFLAG_ASKPWD (1<< 2)
#define XFDCHECKFLAG_AUTOMOUNT (1<< 3)
#define XFDCHECKFLAG_PRINTALL (1<< 4)
#define XFDCHECKFLAG_PRINTEXEC (1<< 5)
#define XFDCHECKFLAG_NODECRUNCH (1<< 6)
#define XFDCHECKFLAG_NOUNLINK (1<< 7)
#define XFDCHECKFLAG_NOUNARCHIVE (1<< 8)
#define XFDCHECKFLAG_NOUNTRACK (1<< 9)
#define XFDCHECKFLAG_NOTRACKCUT (1<<10)
#define XFDCHECKFLAG_NOSTRIP (1<<11)
#define XFDCHECKFLAG_XVSLIB (1<<15)
#define XFDCHECKFLAG_XADLIB (1<<16)
#define XFDCALLFLAGS (XFDCHECKFLAG_SAVE|XFDCHECKFLAG_ALL| \
XFDCHECKFLAG_ASKPWD|XFDCHECKFLAG_AUTOMOUNT| \
XFDCHECKFLAG_PRINTALL|XFDCHECKFLAG_PRINTEXEC| \
XFDCHECKFLAG_NODECRUNCH|XFDCHECKFLAG_NOUNLINK| \
XFDCHECKFLAG_NOUNARCHIVE|XFDCHECKFLAG_NOUNTRACK| \
XFDCHECKFLAG_NOTRACKCUT|XFDCHECKFLAG_NOSTRIP| \
XFDCHECKFLAG_XVSLIB|XFDCHECKFLAG_XADLIB)
#define XFDSAVEFLAGS (XFDCHECKFLAG_LINKED|XFDCHECKFLAG_CRUNCHED| \
XFDCHECKFLAG_STRIPPED)
#define XFDCHECKFLAG_NAMEPRINTED (1<<20)
#define XFDCHECKFLAG_CRUNCHED (1<<21)
#define XFDCHECKFLAG_LINKED (1<<22)
#define XFDCHECKFLAG_ADDRESS (1<<23)
#define XFDCHECKFLAG_NOFREEMEM (1<<24)
#define XFDCHECKFLAG_STRIPPED (1<<25)
#define XFDCHECKFLAG_HIGHDENSITY (1<<26)
#define XADERR_OFFSET 0x100
#define XFDERR_OFFSET 0x200
#define XFDCERR_NOMEMORY 1
#define XFDCERR_EXAMINEERR 2
#define XFDCERR_OPENERR 3
#define XFDCERR_READWRITE 4
#define XFDCERR_SCANERR 5
#define XFDCERR_BREAK 6
#define XFDCERR_OPENDIR 7
#define XFDCERR_NORAD 8
#define XFDCERR_NODOS 9 /* not a dos disk */
#define XFDCERR_RESOURCE 10
#define XFDCERR_NOVIRUS 11
struct FileData {
struct CrunchMemList * fd_MemList;
STRPTR fd_Name;
ULONG fd_LogFileFH;
ULONG fd_SaveDirL;
ULONG fd_Flags;
ULONG fd_NumVirus;
UBYTE fd_RecurseDepth;
UBYTE fd_LinkNum;
UBYTE fd_ArchiveDepth;
UBYTE fd_DDDepth;
UBYTE fd_HDDepth;
};
LONG DoDirectoryScan(STRPTR, STRPTR, struct FileData *);
LONG DoFileOpen(struct FileData *);
void DoMount(ULONG, ULONG);
BPTR GetRad(struct FileData *, STRPTR);
LONG CallSystem(STRPTR);
LONG DoGetVirus(struct FileData *, APTR, ULONG);
LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
LONG DoFileUnLink(struct FileData *, APTR, ULONG);
LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
LONG DoFileStrip(struct FileData *, APTR, ULONG);
void PrintXFDFile(struct FileData *);
void PrintXFDErr(struct FileData *, LONG);
void PrintXFDTxt(struct FileData *, STRPTR, ...);
LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
void FreeCrunchMemList(struct FileData *, APTR);
LONG SaveUncrFile(struct FileData *, APTR, ULONG);
ULONG OpenParentDir(struct FileData *);
ULONG OpenNewDir(struct FileData *, STRPTR);
/* All memory regions must be in mem list. All unneeded memory must be freed
as fast as possible (after unlinking, decrunching), as well as the
MemoryList structure.
The program has a loop like scan routine system, which is called for
every file:
A) Scan files, directories and sub directories and call following for
every file:
1) Check for viruses.
2) Test if it is an archive. When yes decrunch and start with point A.
3) Test if file is linked. When yes unlink and call point 1 for both
parts.
4) Test if file is crunched. When yes, decrunch and start again with
point 1.
5) Try stripping useless stuff. When succesful start with point 1 again.
6) Possibly save file (with SAVE option) or end loop here.
*/
/* main routine, do argument parsing */
LONG start(void)
{
LONG error = RETURN_FAIL;
struct DosLibrary *dosbase;
struct Process *task;
SysBase = (*((struct ExecBase **) 4));
/* test for WB and reply startup-message */
if(!(task = (struct Process *) FindTask(0))->pr_CLI)
{
WaitPort(&task->pr_MsgPort);
Forbid();
ReplyMsg(GetMsg(&task->pr_MsgPort));
return RETURN_FAIL;
}
if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
struct xfdMasterBase *xfdmasterbase;
DOSBase = dosbase;
if((xfdmasterbase = (struct xfdMasterBase *)
OpenLibrary("xfdmaster.library", 37)))
{
struct Args Args;
struct RDArgs *rda;
xfdMasterBase = xfdmasterbase;
memset(&Args, 0, sizeof(struct Args));
if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
{
rda->RDA_ExtHelp =
"FROM source file or directory - may contain patterns\n"
"LOG log file name\n"
"SAVE directory, where decrunched files are saved\n"
"ALL scan deep into directories\n"
"ASKPWD ask for password when needed (needs xpkmaster.library)\n"
"PRINTALL print all filenames\n"
"PRINTEXEC print names of all executable files\n"
"AUTOMOUNT automatically mount RDx: device when needed\n"
"NODECRUNCH do not decrunch files with xfdmaster\n"
"NOUNLINK do not unlink files with xfdmaster\n"
"NOUNARCHIVE do not call archiver for unarchiving file archives\n"
"NOUNTRACK do not call archiver for unarchiving track archives\n"
"NOTRACKCUT do not call archiver for partially track archives\n"
"NOSTRIP do not strip useless hunks\n"
"NOVIRUS do not scan with xvs.library for viruses\n";
if(ReadArgs(PARAM, (LONG *) &Args, rda))
{
ULONG flags = 0, log = 0;
struct xvsBase *xvsbase = 0;
struct xadMasterBase *xadmasterbase = 0;
if(!Args.from) Args.from = "#?";
if(Args.all) flags |= XFDCHECKFLAG_ALL;
if(Args.save) flags |= XFDCHECKFLAG_SAVE;
if(Args.askpwd) flags |= XFDCHECKFLAG_ASKPWD;
if(Args.automount) flags |= XFDCHECKFLAG_AUTOMOUNT;
if(Args.printall) flags |= XFDCHECKFLAG_PRINTALL;
if(Args.printexec) flags |= XFDCHECKFLAG_PRINTEXEC;
if(Args.nodecrunch) flags |= XFDCHECKFLAG_NODECRUNCH;
if(Args.nounlink) flags |= XFDCHECKFLAG_NOUNLINK;
if(Args.nounarchive) flags |= XFDCHECKFLAG_NOUNARCHIVE;
if(Args.nountrack) flags |= XFDCHECKFLAG_NOUNTRACK;
if(Args.notrackcut) flags |= XFDCHECKFLAG_NOTRACKCUT;
if(Args.nostrip) flags |= XFDCHECKFLAG_NOSTRIP;
if(!Args.novirus)
{
if((xvsbase = (struct xvsBase *) OpenLibrary("xvs.library", 33)))
{
flags |= XFDCHECKFLAG_XVSLIB;
xvsBase = xvsbase;
}
}
if(!Args.nounarchive || !Args.nountrack)
{
if((xadmasterbase = (struct xadMasterBase *) OpenLibrary("xadmaster.library", 1)))
{
flags |= XFDCHECKFLAG_XADLIB;
xadMasterBase = xadmasterbase;
}
}
if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
{
struct FileData fd;
APTR win;
ULONG s1 = 0, s2 = 0, msecs;
struct IntuitionBase *intuitionbase;
win = task->pr_WindowPtr;
task->pr_WindowPtr = (APTR) -1;
/* prevent dos requests */
if(log)
SetFileSize(log, 0, OFFSET_BEGINNING);
memset(&fd, 0, sizeof(struct FileData));
fd.fd_Flags = flags;
fd.fd_LogFileFH = log;
if(!xvsbase)
{
Printf("Virus-Checking disabled!\n");
if(log)
FPrintf(log, "Virus-Checking disabled!\n");
}
if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
{
ASSIGN_INT
CurrentTime(&s1, &msecs);
}
error = DoDirectoryScan(Args.from, Args.save, &fd);
task->pr_WindowPtr = win;
if(intuitionbase)
{
CurrentTime(&s2, &msecs);
s2 -= s1;
s1 = s2 / 60;
s2 %= 60;
msecs = s1 / 60;
s1 %= 60;
Printf("\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
if(log)
FPrintf(log, "\nTime needed for check: %2ld:%02ld:%02ld\n", msecs, s1, s2);
CloseLibrary((struct Library *) intuitionbase);
}
if(fd.fd_NumVirus)
{
Printf("The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
if(log)
FPrintf(log, "The scan detected %ld virus%s.\n", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
}
if(log)
Close(log);
}
if(xvsbase)
CloseLibrary((struct Library *) xvsbase);
if(xadmasterbase)
CloseLibrary((struct Library *) xadmasterbase);
FreeArgs(rda);
}
FreeDosObject(DOS_RDARGS, rda);
}
CloseLibrary((struct Library *) xfdmasterbase);
}
CloseLibrary((struct Library *) dosbase);
}
return (error ? RETURN_FAIL : RETURN_OK);
}
/* This scans a directory and calls DoFileOpen for every file. It
automatically creates SAVE destination directories when necessary. */
LONG DoDirectoryScan(STRPTR name, STRPTR sav, struct FileData *fd)
{
struct AnchorPath *APath;
LONG error = XFDCERR_SCANERR;
ULONG retval;
if(!(fd->fd_Flags & XFDCHECKFLAG_SAVE) || !sav ||
(fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
{
if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
512, MEMF_PUBLIC|MEMF_CLEAR)))
{
fd->fd_Name = APath->ap_Buf;
APath->ap_Strlen = 256;
for(retval = MatchFirst(name, APath); !retval;
retval = MatchNext(APath))
{
if(APath->ap_Flags & APF_DIDDIR)
{
OpenParentDir(fd);
APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
}
else if(APath->ap_Info.fib_DirEntryType > 0)
{
if(fd->fd_Flags & XFDCHECKFLAG_ALL)
{
OpenNewDir(fd, APath->ap_Info.fib_FileName);
APath->ap_Flags |= APF_DODIR;
}
}
else
{
PrintXFDErr(fd, DoFileOpen(fd));
fd->fd_Flags &= XFDCALLFLAGS;
fd->fd_LinkNum = 0;
while(fd->fd_MemList)
FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
}
if((fd->fd_Flags & XFDCHECKFLAG_SAVE) && !fd->fd_SaveDirL)
{
error = XFDCERR_OPENDIR; break;
}
if(CTRL_C)
{
error = XFDCERR_BREAK; break;
}
}
MatchEnd(APath);
if(retval == ERROR_NO_MORE_ENTRIES)
error = 0;
FreeMem(APath, sizeof(struct AnchorPath) + 512);
}
else
error = XFDCERR_NOMEMORY;
if(sav && fd->fd_SaveDirL)
UnLock(fd->fd_SaveDirL);
}
else
error = XFDCERR_OPENDIR;
return error;
}
/* Open a file and call DoGetVirus to scan */
LONG DoFileOpen(struct FileData *fd)
{
struct FileInfoBlock *fib;
LONG ret = 0;
if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
{
ULONG fh;
if(fd->fd_ArchiveDepth) /* prevent scan errors */
SetProtection(fd->fd_Name, 0); /* set RWED bits */
if((fh = Open(fd->fd_Name, MODE_OLDFILE)))
{
if(ExamineFH(fh, fib))
{
APTR mem;
if(!fib->fib_Size)
;
else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
{
if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
ret = XFDCERR_READWRITE;
else if(!(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
{
if((fd->fd_Flags & XFDCHECKFLAG_PRINTALL) ||
((fd->fd_Flags & XFDCHECKFLAG_PRINTEXEC) && fib->fib_Size > 4
&& *((ULONG *)mem) == HUNK_HEADER))
PrintXFDFile(fd);
ret = DoGetVirus(fd, mem, fib->fib_Size);
}
}
else
ret = XFDCERR_NOMEMORY;
}
else
ret = XFDCERR_EXAMINEERR;
Close(fh);
}
else
ret = XFDCERR_OPENERR;
FreeDosObject(DOS_FIB, fib);
}
else
ret = XFDCERR_NOMEMORY;
return ret;
}
/* for SAVE option: open parent directory and try to delete the directory
we leave. This only succeeds, when the directory is empty. */
ULONG OpenParentDir(struct FileData *fd)
{
ULONG g;
UBYTE name[300];
if((g = fd->fd_SaveDirL))
{
NameFromLock(g, name, 300);
fd->fd_SaveDirL = ParentDir(g);
UnLock(g);
DeleteFile(name);
}
else
return -1;
return fd->fd_SaveDirL;
}
/* Open a new subdirectory for SAVE option */
ULONG OpenNewDir(struct FileData *fd, STRPTR name)
{
ULONG g;
if(fd->fd_SaveDirL)
{
g = CurrentDir(fd->fd_SaveDirL);
if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
if((fd->fd_SaveDirL = CreateDir(name)))
ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
UnLock(CurrentDir(g));
}
else
return -1;
return fd->fd_SaveDirL;
}
void DoMount(ULONG deep, ULONG hd)
{
ULONG fh;
UBYTE buf[50], buf2[60];
sprintf(buf, "T:CheckMountList_%08lx_%03ld", FindTask(0), deep);
if((fh = Open(buf, MODE_NEWFILE)))
{
FPrintf(fh,
"R%lc%ld:\n"
"\tDevice\t\t= ramdrive.device\n"
"\tUnit\t\t= %3ld\n"
"\tSurfaces\t= 2\n"
"\tBlocksPerTrack\t= %ld\n"
"\tReserved\t= 2\n"
"\tInterleave\t= 0\n"
"\tLowCyl\t\t= 0\n"
"\tHighCyl\t\t= 79\n"
"\tBootPri\t\t= -10\n"
"\tBuffers\t\t= 5\n"
"\tBufMemType\t= 1\n#\n", hd ? 'H' : 'D', deep, (hd ? 50 : 10) + deep,
hd ? 22 : 11);
Close(fh);
sprintf(buf2, "Mount R%lc%ld: FROM %s", hd ? 'H' : 'D', deep, buf);
/* I could do this myself, but I don't know, if it is the correct
method, so I use Mount command. */
CallSystem(buf2);
DeleteFile(buf);
}
}
/* Try to get RDx: disk and initialize it. */
BPTR GetRad(struct FileData *fd, STRPTR rname)
{
UBYTE name[20];
sprintf(name, NAME "%03ld", fd->fd_ArchiveDepth);
if(Inhibit(rname, 1))
{
Format(rname, name, ID_DOS_DISK);
Inhibit(rname, 0);
return Lock(rname, SHARED_LOCK);
}
else
{
LONG i, m = 0;
UBYTE name2[20];
struct DosList *dosl;
if((dosl = LockDosList(LDF_DEVICES|LDF_READ)))
{
i = strlen(rname);
name2[--i] = 0;
while(i--)
name2[i] = rname[i];
dosl = FindDosEntry(dosl, name2, LDF_DEVICES);
UnLockDosList(LDF_DEVICES|LDF_READ);
if(!dosl && (fd->fd_Flags & XFDCHECKFLAG_AUTOMOUNT))
{
DoMount(fd->fd_ArchiveDepth, fd->fd_Flags &
XFDCHECKFLAG_HIGHDENSITY);
m = 1;
}
if(dosl || m)
{
for(i = 0; i < 50; ++i)
{
if(Inhibit(rname, 1))
{
Format(rname, name, ID_DOS_DISK);
Inhibit(rname, 0);
return Lock(rname, SHARED_LOCK);
}
Delay(10);
}
/* clear flag if mount failed */
if(m)
fd->fd_Flags &= ~XFDCHECKFLAG_AUTOMOUNT;
}
}
}
return 0;
}
LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
{
if(fd->fd_Flags & XFDCHECKFLAG_XVSLIB)
{
APTR mem;
if((mem = AllocMem(buflength, MEMF_ANY)))
{
struct xvsFileInfo *fi;
if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
{
ULONG i;
/* xvs may modify the buffer! */
CopyMem(buffer, mem, buflength);
fi->xvsfi_File = mem;
fi->xvsfi_FileLen = buflength;
i = xvsCheckFile(fi);
if(i == XVSFT_DATAVIRUS)
{
PrintXFDTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(i == XVSFT_FILEVIRUS)
{
PrintXFDTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(i == XVSFT_LINKVIRUS)
{
PrintXFDTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
xvsFreeObject(fi);
}
else
PrintXFDErr(fd, XFDCERR_NOVIRUS);
FreeMem(mem, buflength);
}
else
PrintXFDErr(fd, XFDCERR_NOVIRUS);
}
return DoFileUnArchive(fd, buffer, buflength);
}
/* Call command with NIL: input and output. */
LONG CallSystem(STRPTR com)
{
ULONG infh;
LONG err = XFDCERR_RESOURCE;
if((infh = Open("NIL:", MODE_OLDFILE)))
{
ULONG outfh;
if((outfh = Open("NIL:", MODE_NEWFILE)))
{
ULONG i;
if(!(i = SystemTags(com, SYS_Input, infh, SYS_Output, outfh, TAG_DONE)))
err = 0;
Close(outfh);
}
Close(infh);
}
return err;
}
/****************************************************************************/
/**** old Archive stuff, should become obsolete *****/
/****************************************************************************/
#define ARCTYPE_LHA 1
#define ARCTYPE_ZIP 2
#define ARCTYPE_ZOO 3
#define ARCTYPE_LHA_SFX 4
#define ARCTYPE_ARC 5
#define XFDCHECKFLAG_ARCCOPY (1<<27)
#define XFDCHECKFLAG_DIRCHANGE (1<<28)
LONG DoArcNameCheck(struct UnArcData *, STRPTR, ULONG, ULONG,
struct FileData *);
LONG DeleteAll(STRPTR);
struct UnArcData { /* This is allocated to save stack space */
STRPTR uad_ArcName;
UBYTE uad_DestDir[30];
UBYTE uad_DoDestDir[30];
UBYTE uad_CopyArcName[30];
UBYTE uad_Command[200];
};
/* types greater than 100 are disk archives */
#define ARCTYPE_ZOOM 101
/* Test if we need to copy the archive to a temporary file. This is
necessary, because most archivers are not able to handle archives
correctly, when there are pattern characters in the path or archive
name. Also they fail, when the archive name has an incorrect extension.
For Archivers like Zoo and Arc, which dearchive always to current
directory, we need to copy always, as the arcname must have an absolute
path, which is not guarranteed for argument path name, as this may be
relative to current directory.
--> except we are already in a decrunched archive, as here the name is
garanted to be absolute, e.g. start with ':'.
Archives which are crunched with an alien cruncher or are linked must be
copied as well. (If this really exists ???)
In these cases the archive file is copied with a correct filename and
extension, so the archiver works well.
Problem: This needs mem (or disk space when T: is assigned to hard
disk).
*/
LONG DoArcNameCheck(struct UnArcData *uad, STRPTR mem, ULONG buflength,
ULONG arc, struct FileData *fd)
{
STRPTR p;
LONG err = 0;
for(p = uad->uad_ArcName; *p; ++p)
{
if(*p == '#' || *p == '(' || *p == ')' || *p == '[' || *p == ']'
|| *p == '*' || *p == '~' || *p == '#' || *p == '?' || *p == '|')
fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
}
if((fd->fd_Flags & (XFDCHECKFLAG_CRUNCHED|XFDCHECKFLAG_LINKED)) ||
((fd->fd_Flags & XFDCHECKFLAG_DIRCHANGE) && !fd->fd_ArchiveDepth))
fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
else if(!(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY))
{
if((p -= 4) <= uad->uad_ArcName) /* position of extension */
p = uad->uad_ArcName+1; /* at least one char as name is needed */
switch(arc)
{
case ARCTYPE_LHA:
if(stricmp(p, ".lha") && stricmp(p, ".lzh"))
fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
break;
case ARCTYPE_ZIP:
if(stricmp(p, ".zip")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
break;
case ARCTYPE_LHA_SFX:
if(stricmp(p, ".run")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
break;
case ARCTYPE_ARC:
if(stricmp(p, ".arc")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
break;
case ARCTYPE_ZOO:
if(stricmp(p, ".zoo")) fd->fd_Flags |= XFDCHECKFLAG_ARCCOPY;
break;
}
}
if(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY)
{
ULONG d;
switch(arc)
{
case ARCTYPE_LHA:
p = ".lha"; break;
case ARCTYPE_ZIP:
p = ".zip"; break;
case ARCTYPE_ZOO:
p = ".zoo"; break;
case ARCTYPE_LHA_SFX:
p = ".run"; break;
case ARCTYPE_ARC:
p = ".arc"; break;
case ARCTYPE_ZOOM:
p = ".zom"; break;
}
sprintf(uad->uad_CopyArcName, "T:CheckArc_%08lx_%03ld%s", FindTask(0),
fd->fd_ArchiveDepth, p);
uad->uad_ArcName = uad->uad_CopyArcName;
if((d = Open(uad->uad_ArcName, MODE_NEWFILE)))
{
if(Write(d, mem, buflength) != buflength)
err = XFDCERR_READWRITE;
Close(d);
}
else
err = XFDCERR_OPENERR;
}
return err;
}
/* Tests if a file is an archive. When yes, the archive is unarchived and
DoDirectoryScan is called for the result files. Else DoFileUnLink is
called.
*/
LONG DoFileUnArchiveOld(struct FileData *fd, APTR buffer, ULONG buflength)
{
ULONG arc = 0;
STRPTR mem = (STRPTR) buffer;
LONG err = 0;
if(buflength > 7 && mem[2] == '-' && mem[3] == 'l' && mem[4] == 'h'
&& mem[6] == '-')
{ /* This is an LhA-File */
arc = ARCTYPE_LHA;
PrintXFDTxt(fd, "LhA (ARCHIVE)");
}
else if(buflength > 4 && mem[0] == 'P' && mem[1] == 'K' && mem[2] == 3
&& mem[3] == 4)
{
arc = ARCTYPE_ZIP;
PrintXFDTxt(fd, "Zip (ARCHIVE)");
}
else if(buflength > 4 && mem[0] == 'Z' && mem[1] == 'O' && mem[2] == 'O'
&& mem[3] == ' ' && mem[5] == '.')
{
arc = ARCTYPE_ZOO;
fd->fd_Flags |= XFDCHECKFLAG_DIRCHANGE;
PrintXFDTxt(fd, "ZOO (ARCHIVE)");
}
else if(buflength > 4 && mem[0x2C] == 'S' && mem[0x2D] == 'F' &&
mem[0x2E] == 'X' && mem[0x2F] == '!' && *((ULONG *)mem) == 0x3F3)
{
arc = ARCTYPE_LHA_SFX;
PrintXFDTxt(fd, "LhA SFX (ARCHIVE)");
}
else if(buflength > 2 && mem[0] == 0x1A && mem[1] && mem[1] < 9)
{ /* This detection is very unsecure !!! */
arc = ARCTYPE_ARC;
fd->fd_Flags |= XFDCHECKFLAG_DIRCHANGE;
PrintXFDTxt(fd, "Arc (ARCHIVE)");
}
else if(buflength > 4 && mem[0] == 'Z' && mem[1] == 'O' && mem[2] == 'M'
&& mem[3] == '5')
{
arc = ARCTYPE_ZOOM;
PrintXFDTxt(fd, "Zoom (ARCHIVE)");
}
if(arc)
{
if((arc < 100 && !(fd->fd_Flags & XFDCHECKFLAG_NOUNARCHIVE)) ||
(arc >= 100 && !(fd->fd_Flags & XFDCHECKFLAG_NOUNTRACK)))
{
struct UnArcData *uad;
if((uad = (struct UnArcData *) AllocMem(sizeof(struct UnArcData),
MEMF_ANY)))
{ /* AllocMem to prevent stack overflow */
uad->uad_ArcName = fd->fd_Name;
err = DoArcNameCheck(uad, mem, buflength, arc, fd);
FreeCrunchMemList(fd, mem);
if(!err && !OpenNewDir(fd, FilePart(fd->fd_Name)))
err = XFDCERR_OPENERR;
if(!err)
{
ULONG destdir, storedir = 0;
if(arc > 100)
{
sprintf(uad->uad_DestDir, "RD%ld:", fd->fd_DDDepth);
strcpy(uad->uad_DoDestDir, uad->uad_DestDir);
if((destdir = GetRad(fd, uad->uad_DestDir)))
{
UnLock(destdir);
sprintf(uad->uad_Command, "ZOOM NOPROMPT FROM \"%s\" TO %s",
uad->uad_ArcName, uad->uad_DestDir);
err = CallSystem(uad->uad_Command);
if(!(destdir = Lock(uad->uad_DestDir, SHARED_LOCK)) && !err)
err = XFDCERR_NODOS;
}
else
err = XFDCERR_NORAD;
}
else
{
sprintf(uad->uad_DestDir, "T:CheckX_%08lx_%03ld",
FindTask(0), fd->fd_ArchiveDepth);
sprintf(uad->uad_DoDestDir, "T:CheckX_%08lx_%03ld/#?",
FindTask(0), fd->fd_ArchiveDepth);
if((destdir = CreateDir(uad->uad_DestDir)))
{
ChangeMode(CHANGE_LOCK, destdir, SHARED_LOCK);
if(fd->fd_Flags & XFDCHECKFLAG_DIRCHANGE)
storedir = CurrentDir(destdir);
switch(arc)
{
case ARCTYPE_LHA: case ARCTYPE_LHA_SFX:
sprintf(uad->uad_Command, "Lha -IMmq x \"%s\" %s/",
uad->uad_ArcName, uad->uad_DestDir);
break;
case ARCTYPE_ZIP:
sprintf(uad->uad_Command, "UnZip \"%s\" -d %s/",
uad->uad_ArcName, uad->uad_DestDir);
break;
case ARCTYPE_ZOO:
sprintf(uad->uad_Command, "Zoo x//qqq \"%s\"",
uad->uad_ArcName);
break;
case ARCTYPE_ARC:
sprintf(uad->uad_Command, "Arc xwn \"%s\"",
uad->uad_ArcName);
break;
}
err = CallSystem(uad->uad_Command);
}
else
err = XFDCERR_OPENDIR;
}
if(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY)
{ /* save some memory */
fd->fd_Flags &= ~XFDCHECKFLAG_ARCCOPY;
DeleteFile(uad->uad_ArcName);
}
if(destdir)
{
if(!err)
{
struct FileData fdp;
CopyMem(fd, &fdp, sizeof(struct FileData));
fdp.fd_Flags = (fdp.fd_Flags&XFDCALLFLAGS)|XFDCHECKFLAG_ALL;
++fdp.fd_ArchiveDepth;
++fdp.fd_RecurseDepth;
fdp.fd_MemList = 0;
if(arc > 100)
++fdp.fd_DDDepth;
err = DoDirectoryScan(uad->uad_DoDestDir, 0, &fdp);
fd->fd_SaveDirL = fdp.fd_SaveDirL;
fd->fd_NumVirus = fdp.fd_NumVirus;
}
if(fd->fd_Flags & XFDCHECKFLAG_DIRCHANGE)
CurrentDir(storedir);
UnLock(destdir);
if(arc < 100)
DeleteAll(uad->uad_DestDir);
}
if(!OpenParentDir(fd))
err = XFDCERR_OPENDIR;
}
if(fd->fd_Flags & XFDCHECKFLAG_ARCCOPY)
DeleteFile(uad->uad_ArcName);
FreeMem(uad, sizeof(struct UnArcData));
}
else
err = XFDCERR_NOMEMORY;
}
}
else
err = DoFileUnLink(fd, buffer, buflength);
return err;
}
/* This deletes a temporary directory and all files in it.
It returns 0 on error and gets name of directory to delete.
*/
LONG DeleteAll(STRPTR name)
{
LONG retval;
struct AnchorPath *APath;
STRPTR fname;
if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
512, MEMF_PUBLIC|MEMF_CLEAR)))
{
APath->ap_Strlen = 256;
fname = (STRPTR) APath->ap_Buf + 256;
for(retval = MatchFirst(name, APath); !retval; retval = MatchNext(APath))
{
if(*fname)
{
SetProtection(fname, 0); /* set RWED bits */
DeleteFile(fname);
}
CopyMem(APath->ap_Buf, fname, 256);
if(APath->ap_Flags & APF_DIDDIR)
APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
else if(APath->ap_Info.fib_DirEntryType > 0) /* a directory */
{
APath->ap_Flags |= APF_DODIR; *fname = 0;
}
}
MatchEnd(APath);
FreeMem(APath, sizeof(struct AnchorPath) + 512);
}
return DeleteFile(name); /* when this returns error, then any of the
above functions may have failed --> directory not empty. */
}
/****************************************************************************/
/* Tests if a file is an archive. When yes, the archive is unarchived and
DoDirectoryScan is called for the result files. Else DoFileUnLink is
called.
*/
LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG err = 0;
if(fd->fd_Flags & XFDCHECKFLAG_XADLIB)
{
struct xadArchiveInfo *ai;
if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
{
if(!xadGetInfo(ai, XAD_INMEMORY, buffer, XAD_INSIZE, buflength,
TAG_DONE))
{
STRPTR arcname;
arcname = fd->fd_Name;
if(ai->xai_Flags & XADAIF_FILECORRUPT)
PrintXFDTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
else
PrintXFDTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
if(!(!(fd->fd_Flags & XFDCHECKFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
!(fd->fd_Flags & XFDCHECKFLAG_NOUNTRACK) && ai->xai_DiskInfo))
err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
err = XFDCERR_OPENERR;
else
{
if(!(fd->fd_Flags & XFDCHECKFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
{
struct xadFileInfo *fi;
fi = ai->xai_FileInfo;
while(!CTRL_C && fi)
{
APTR dest;
if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
{
ULONG flags;
flags = fd->fd_Flags;
fd->fd_Flags &= ~XFDCHECKFLAG_NAMEPRINTED;
fd->fd_Name = fi->xfi_FileName;
fd->fd_RecurseDepth++;
fd->fd_ArchiveDepth++;
if((dest = AllocMem(fi->xfi_Size, MEMF_PUBLIC)))
{
if(!(err = AddCrunchMemList(fd, dest, fi->xfi_Size)))
{
if((err = xadFileUnArc(ai, XAD_OUTMEMORY, dest, XAD_OUTSIZE,
fi->xfi_Size, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE)))
err += XADERR_OFFSET;
else
{
if((fd->fd_Flags & XFDCHECKFLAG_PRINTALL) ||
((fd->fd_Flags & XFDCHECKFLAG_PRINTEXEC) && fi->xfi_Size > 4
&& *((ULONG *)dest) == HUNK_HEADER))
PrintXFDFile(fd);
err = DoGetVirus(fd, dest, fi->xfi_Size);
}
FreeCrunchMemList(fd, dest);
}
else
FreeMem(dest, fi->xfi_Size);
}
else
err = XFDCERR_NOMEMORY;
if(err)
{
PrintXFDErr(fd, err);
err = 0;
}
--fd->fd_RecurseDepth;
--fd->fd_ArchiveDepth;
fd->fd_Flags = flags;
}
fi = fi->xfi_Next;
}
}
if(!(fd->fd_Flags & XFDCHECKFLAG_NOUNTRACK) && ai->xai_DiskInfo)
{
struct DiskInfoData {
UBYTE name[10];
UBYTE buf[50];
BPTR destdir;
ULONG geom;
} *d;
/* reduce stacksize, as we have a recursive program */
if((d = AllocMem(sizeof(struct DiskInfoData), MEMF_PUBLIC)))
{
struct xadDiskInfo *di;
di = ai->xai_DiskInfo;
while(!CTRL_C && di)
{
if(di->xdi_SectorSize != 512 || di->xdi_Heads != 2 ||
di->xdi_Cylinders != 80 || (di->xdi_TrackSectors != 11 &&
di->xdi_TrackSectors != 22))
{
sprintf(d->buf, "-disk image %ld (unsupported geometry)", di->xdi_EntryNumber);
d->geom = 1;
}
else
{
d->geom = 0;
if(di->xdi_TrackSectors == 11)
sprintf(d->name, "RD%ld:", fd->fd_DDDepth);
else
{
fd->fd_Flags |= XFDCHECKFLAG_HIGHDENSITY;
sprintf(d->name, "RH%ld:", fd->fd_HDDepth);
}
if(di->xdi_LowCyl || di->xdi_HighCyl != 79)
sprintf(d->buf, "-disk image %ld (%s, %ld to %ld)",
di->xdi_EntryNumber, fd->fd_Flags & XFDCHECKFLAG_HIGHDENSITY ?
"HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
else
sprintf(d->buf, "-disk image %ld (%s)",
di->xdi_EntryNumber, fd->fd_Flags & XFDCHECKFLAG_HIGHDENSITY ?
"HD" : "DD");
}
fd->fd_Name = d->buf;
PrintXFDFile(fd);
if(di->xdi_TextInfo)
{
struct xadTextInfo *ti;
ULONG flags, i = 1;
for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
{
if(ti->xti_Size && ti->xti_Text)
{
flags = fd->fd_Flags;
fd->fd_Flags &= ~XFDCHECKFLAG_NAMEPRINTED;
fd->fd_Flags |= XFDCHECKFLAG_NOFREEMEM;
fd->fd_RecurseDepth++;
sprintf(d->buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
if((fd->fd_Flags & XFDCHECKFLAG_PRINTALL) ||
((fd->fd_Flags & XFDCHECKFLAG_PRINTEXEC) && ti->xti_Size > 4
&& *((ULONG *)(ti->xti_Text)) == HUNK_HEADER))
PrintXFDFile(fd);
PrintXFDErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
--fd->fd_RecurseDepth;
fd->fd_Flags = flags;
}
++i;
}
}
if(!d->geom)
{
if((di->xdi_LowCyl == 0 && di->xdi_HighCyl == 79) ||
!(fd->fd_Flags & XFDCHECKFLAG_NOTRACKCUT))
{
if((d->destdir = GetRad(fd, d->name)))
{
struct xadDeviceInfo *dvi;
UnLock(d->destdir);
if((dvi = (struct xadDeviceInfo *)
xadAllocObjectA(XADOBJ_DEVICEINFO, 0)))
{
d->name[strlen(d->name)-1] = 0;
dvi->xdi_DOSName = d->name;
err = xadDiskUnArc(ai, XAD_OUTDEVICE, dvi,
XAD_ENTRYNUMBER, di->xdi_EntryNumber, XAD_VERIFY,
TRUE, TAG_DONE);
xadFreeObjectA(dvi, 0);
d->name[strlen(d->name)] = ':';
}
else
err = XFDCERR_NOMEMORY;
if(err)
{
PrintXFDErr(fd, XADERR_OFFSET+err); err = 0;
}
else if(!(d->destdir = Lock(d->name, SHARED_LOCK)))
PrintXFDErr(fd, XFDCERR_NODOS);
else
{
struct FileData fdp;
CopyMem(fd, &fdp, sizeof(struct FileData));
fdp.fd_Flags = (fdp.fd_Flags&XFDCALLFLAGS)|XFDCHECKFLAG_ALL;
fdp.fd_MemList = 0;
fdp.fd_ArchiveDepth++;
fdp.fd_RecurseDepth++;
if(fd->fd_Flags & XFDCHECKFLAG_HIGHDENSITY)
++fdp.fd_HDDepth;
else
++fdp.fd_DDDepth;
PrintXFDErr(fd, DoDirectoryScan(d->name, 0, &fdp));
fd->fd_SaveDirL = fdp.fd_SaveDirL;
fd->fd_NumVirus = fdp.fd_NumVirus;
UnLock(d->destdir);
}
}
else
PrintXFDErr(fd, XFDCERR_NORAD);
}
}
di = di->xdi_Next;
} /* while */
FreeMem(d, sizeof(struct DiskInfoData));
} /* AllocMem DiskInfoData */
else
err = XFDCERR_NOMEMORY;
} /* is there is disk entry? */
if(!OpenParentDir(fd))
err = XFDCERR_OPENDIR;
}
fd->fd_Name = arcname;
}
else
err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
xadFreeObjectA(ai, 0);
}
else
err = XFDCERR_NOMEMORY;
}
else
err = DoFileUnArchiveOld(fd, buffer, buflength); /* later DoFileUnLink */
return err;
}
/* Tries to unlink a file. When the file was linked, we call DoGetVirus
for the two parts to check if they may be archives, else we call
DoFileUnCrunch.
*/
LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = XFDCERR_NOMEMORY;
struct xfdLinkerInfo *xli;
if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
{
xli->xfdli_Buffer = buffer;
xli->xfdli_BufLen = buflength;
if(xfdRecogLinker(xli))
{
PrintXFDTxt(fd, xli->xfdli_LinkerName);
if(fd->fd_Flags & XFDCHECKFLAG_NOUNLINK)
ret = DoFileUnCrunch(fd, buffer, buflength);
else if(xfdUnlink(xli))
{
ULONG flags;
fd->fd_Flags |= XFDCHECKFLAG_LINKED;
++fd->fd_RecurseDepth;
++fd->fd_LinkNum;
flags = fd->fd_Flags;
fd->fd_Flags |= XFDCHECKFLAG_NOFREEMEM;
PrintXFDErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
xli->xfdli_SaveLen1));
fd->fd_Flags = flags; /* XFDCHECKFLAG_NOFREEMEM is cleared */
PrintXFDErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
xli->xfdli_SaveLen2));
ret = 0;
--fd->fd_RecurseDepth;
}
else
ret = XFDERR_OFFSET + xli->xfdli_Error;
}
else
ret = DoFileUnCrunch(fd, buffer, buflength);
xfdFreeObject(xli);
}
return ret;
}
/* Tries to decrunch a file. When it is crunched, we decrunch it and call
DoGetVirus to start the loop again. Else we call unstripping.
*/
LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = XFDCERR_NOMEMORY;
struct xfdBufferInfo *xbi;
if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
{
xbi->xfdbi_SourceBuffer = buffer;
xbi->xfdbi_SourceBufLen = buflength;
xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
if(xfdRecogBuffer(xbi))
{
struct Library *xpkbase;
STRPTR buf = 0;
ULONG buflen = 0;
PrintXFDTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
"%s", xbi->xfdbi_PackerName);
if(fd->fd_Flags & XFDCHECKFLAG_ASKPWD && (xpkbase =
OpenLibrary(XPKNAME, 4)))
{
ASSIGN_XPK
if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
{
buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
xbi->xfdbi_MaxSpecialLen;
if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
{
if(!XpkPassRequestTags(XPK_PasswordBuf, buf,
XPK_PassBufSize, buflen, TAG_DONE))
xbi->xfdbi_Special = buf;
}
}
else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
{
if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, TAG_DONE))
xbi->xfdbi_Special = &buflen;
}
else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
{
if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, TAG_DONE))
xbi->xfdbi_Special = &buflen;
}
CloseLibrary(xpkbase);
}
if(fd->fd_Flags & XFDCHECKFLAG_NODECRUNCH)
ret = DoFileStrip(fd, buffer, buflength);
else if(xfdDecrunchBuffer(xbi))
{
if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
!(fd->fd_Flags & XFDCHECKFLAG_ADDRESS))
{
fd->fd_Flags |= XFDCHECKFLAG_ADDRESS;
PrintXFDErr(fd, SaveUncrFile(fd, buffer, buflength));
}
fd->fd_Flags |= XFDCHECKFLAG_CRUNCHED;
FreeCrunchMemList(fd, buffer);
++fd->fd_RecurseDepth;
if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufLen)))
{
PrintXFDErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufSaveLen));
}
--fd->fd_RecurseDepth;
}
else
ret = XFDERR_OFFSET + xbi->xfdbi_Error;
if(buf)
FreeMem(buf, buflen);
}
else
ret = DoFileStrip(fd, buffer, buflength);
xfdFreeObject(xbi);
}
return ret;
}
/* Tries to strip useless hunks in a file. When there are some, we remove
them and call DoGetVirus to start the loop again. Else we finish.
When either unlinking or uncrunching happend in before loops, we may
save the file when there was SAVE option.
*/
LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = 0;
ULONG reslength = buflength;
if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
XFDCHECKFLAG_NOSTRIP))
xfdStripHunks(buffer, buflength, &reslength,
XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
/* errors are not interpreted */
if(buflength > reslength)
{
fd->fd_Flags |= XFDCHECKFLAG_STRIPPED;
PrintXFDTxt(fd, "%ld bytes stripped", buflength-reslength);
ret = DoGetVirus(fd, buffer, reslength);
}
if(!ret && !(fd->fd_Flags & XFDCHECKFLAG_ADDRESS))
ret = SaveUncrFile(fd, buffer, buflength);
FreeCrunchMemList(fd, buffer);
return ret;
}
/* Print file name */
void PrintXFDFile(struct FileData *fd)
{
STRPTR name = fd->fd_Name;
UBYTE i;
if(fd->fd_ArchiveDepth) /* skip that ugly T:CheckX.. or RD?: */
{
if(*name == 'R' && (name[1] == 'D' || name[1] == 'H'))
{
while(*name != ':')
++name;
++name;
}
else if(*name == 'T' && name[1] == ':') /* becomes obsolete with Archive stuff remove */
{
while(*name != '/')
++name;
++name;
}
}
if(fd->fd_LogFileFH)
{
for(i = 0; i < fd->fd_ArchiveDepth; ++i)
FPutC(fd->fd_LogFileFH, '*');
FPrintf(fd->fd_LogFileFH, "%s\n", name);
}
for(i = 0; i < fd->fd_ArchiveDepth; ++i)
FPutC(Output(), '*');
Printf("%s\n", name);
fd->fd_Flags |= XFDCHECKFLAG_NAMEPRINTED;
}
/* Print Error - Error 100 and up are CheckX special errors. */
void PrintXFDErr(struct FileData *fd, LONG err)
{
if(err)
{
STRPTR txt = 0, txt2;
UBYTE i;
if(err > XFDERR_OFFSET)
{
txt2 = " XFD-Error %ld: %s\n";
err -= XFDERR_OFFSET;
txt = xfdGetErrorText(err);
}
else if(err > XADERR_OFFSET)
{
txt2 = " XAD-Error %ld: %s\n";
err -= XADERR_OFFSET;
txt = xadGetErrorText(err);
}
else
{
txt2 = " CheckX-Error %ld: %s\n";
switch(err)
{
case XFDCERR_NOMEMORY: txt = "not enough memory"; break;
case XFDCERR_EXAMINEERR: txt = "examining failed"; break;
case XFDCERR_OPENERR: txt = "opening file failed"; break;
case XFDCERR_READWRITE: txt = "read or write failed"; break;
case XFDCERR_SCANERR: txt = "directory scan failed"; break;
case XFDCERR_BREAK: txt = "user break"; break;
case XFDCERR_OPENDIR: txt = "opening directory failed"; break;
case XFDCERR_NORAD: txt = "accessing ramdrive failed"; break;
case XFDCERR_NODOS: txt = "not a dos disk"; break;
case XFDCERR_RESOURCE: txt = "needed resource not available"; break;
case XFDCERR_NOVIRUS: txt = "could not check for virus"; break;
}
}
if(!(fd->fd_Flags & XFDCHECKFLAG_NAMEPRINTED))
PrintXFDFile(fd);
if(fd->fd_LogFileFH)
{
for(i = 0; i < fd->fd_RecurseDepth; ++i)
FPutC(fd->fd_LogFileFH, ' ');
FPrintf(fd->fd_LogFileFH, txt2, err, txt);
Flush(fd->fd_LogFileFH);
}
for(i = 0; i < fd->fd_RecurseDepth; ++i)
FPutC(Output(), ' ');
Printf(txt2, err, txt);
}
}
/* Print type text */
void PrintXFDTxt(struct FileData *fd, STRPTR txt, ...)
{
UBYTE i;
if(!(fd->fd_Flags & XFDCHECKFLAG_NAMEPRINTED))
PrintXFDFile(fd);
if(fd->fd_LogFileFH)
{
for(i = 0; i <= fd->fd_RecurseDepth; ++i)
FPutC(fd->fd_LogFileFH, ' ');
VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
FPutC(fd->fd_LogFileFH, '\n');
Flush(fd->fd_LogFileFH);
}
for(i = 0; i <= fd->fd_RecurseDepth; ++i)
FPutC(Output(), ' ');
VPrintf(txt, &txt+1);
FPutC(Output(), '\n');
}
/* Add memory to the memory list. */
LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
{
struct CrunchMemList *ml;
if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
MEMF_ANY)))
{
ml->cml_Next = fd->fd_MemList;
ml->cml_MemoryRegion = reg;
ml->cml_MemorySize = size;
fd->fd_MemList = ml;
}
else
{
FreeMem(reg, size);
return XFDCERR_NOMEMORY;
}
return 0;
}
/* Free memory from the memory list. */
void FreeCrunchMemList(struct FileData *fd, APTR reg)
{
struct CrunchMemList mc, *ml = &mc;
if(fd->fd_Flags & XFDCHECKFLAG_NOFREEMEM)
return;
for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
{
if(ml->cml_Next->cml_MemoryRegion == reg)
{
struct CrunchMemList *m;
m = ml->cml_Next;
ml->cml_Next = m->cml_Next;
FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
FreeMem(m, sizeof(struct CrunchMemList));
}
}
fd->fd_MemList = mc.cml_Next;
}
/* Save file, when SAVE option and file was crunched or linked. */
LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
{
BPTR filefh, cd;
LONG ret = 0, i = 0;
UBYTE name[50];
UBYTE nbuf[256];
if(!(fd->fd_SaveDirL && (fd->fd_Flags & XFDSAVEFLAGS)))
return 0;
sprintf(name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
fd->fd_LinkNum);
cd = CurrentDir(fd->fd_SaveDirL);
while(!ret && name[i])
{
for(;name[i] && name[i] != '/'; ++i)
nbuf[i] = name[i];
if(name[i] == '/')
{
nbuf[i] = 0;
if((filefh = Lock(nbuf, SHARED_LOCK)))
UnLock(filefh);
else
{
if((filefh = CreateDir(nbuf)))
UnLock(filefh);
else
ret = XFDCERR_OPENERR;
}
nbuf[i] = name[i];
++i;
}
}
if(!ret)
{
if((filefh = Open(name, MODE_NEWFILE)))
{
if(Write(filefh, buf, size) != size)
ret = XFDCERR_READWRITE;
Close(filefh);
}
else
ret = XFDCERR_OPENERR;
}
CurrentDir(cd);
return ret;
}